#include "bsp_timer.h"

static SOFT_TMR s_tTmr[TMR_COUNT];

// 程序运行时间
__IO int32_t g_iRunTime = 0;

#if defined (USE_TIM3)
	static void bsp_InitHardTimer(void);
#endif

static void bsp_SoftTimerDec(SOFT_TMR *_tmr);

/* 保存 TIM定时中断到后执行的回调函数指针 */
void (*s_TIM_CallBack1)(void);


/* 定时器初始化 */
void bsp_InitTimer(void)
{
	uint8_t i;

	for(i=0; i<TMR_COUNT; i++)
	{
		s_tTmr[i].Count = 0;
		s_tTmr[i].Flag = 0;
		s_tTmr[i].PreLoad = 0;
		s_tTmr[i].Mode = TMR_ONCE_MODE;		// 初始化为单次模式
	}

#if defined (USE_TIM3)	
	bsp_InitHardTimer();
#endif
}

/* 本例程主要使用借助systick中断实现软件定时器， 并没有真正用上TIMER外设*/
#if defined (USE_TIM3)
static void bsp_InitHardTimer(void)
{
	MX_TIM3_Init();
}
#endif


/* systick回调函数,软件定时器的核心,这里时基为1ms */
void HAL_SYSTICK_Callback(void)
{
	static uint8_t s_count = 0;
	uint8_t i;

	for(i=0; i<TMR_COUNT; i++)
	{
		bsp_SoftTimerDec(&s_tTmr[i]);
	}

	g_iRunTime++;
	if(g_iRunTime == 0x7FFFFFFF)	// int32_t类型最大值
	{
		g_iRunTime = 0;
	}

	bsp_RunPer1ms();

	if(++s_count >= 10)
	{
		s_count = 0;
		bsp_RunPer10ms();
	}
}

/* 定时对软件定时器计数值减1 */
static void bsp_SoftTimerDec(SOFT_TMR *_tmr)
{
	if(_tmr->Count > 0)
	{
		// 计数值递减
		if(--_tmr->Count == 0)
		{
			_tmr->Flag = 1;		// 时间到达，标志置1

			// 自动模式重新装载值
			if(_tmr->Mode == TMR_AUTO_MODE)
			{
				_tmr->Count = _tmr->PreLoad;
			}
		}
	}
}

/**
 * @brief		启动定时器，并设置周期
 * @param		_id: 定时器ID号
 * @param		_period: 周期值
 * @retval	None
 * @note		默认使用单次模式
 */
void bsp_StartTimer(uint8_t _id, uint32_t _period)
{
	if(_id > TMR_COUNT)
	{
		printf("Timer ID Error!\n");
		return ;
	}

	DISABLE_INT();

	s_tTmr[_id].Count = _period;			// 计数值
	s_tTmr[_id].PreLoad = _period;		// 预装载值，仅自动模式有用
	s_tTmr[_id].Flag = 0;							// 复位定时时间到标志
	s_tTmr[_id].Mode = TMR_ONCE_MODE;	// 单次模式

	ENABLE_INT();
}

/**
 * @brief		启动自动定时器，并设置周期
 * @param		_id: 定时器ID号
 * @param		_period: 周期值
 * @retval	None
 * @note		默认使用自动模式
 */
void bsp_StartAutoTimer(uint8_t _id, uint32_t _period)
{
	if(_id > TMR_COUNT)
	{
		printf("Timer ID Error!\n");
		return ;
	}

	DISABLE_INT();

	s_tTmr[_id].Count = _period;			// 计数值
	s_tTmr[_id].PreLoad = _period;		// 预装载值，仅自动模式有用
	s_tTmr[_id].Flag = 0;							// 复位定时时间到标志
	s_tTmr[_id].Mode = TMR_AUTO_MODE;	// 自动模式

	ENABLE_INT();
}

/* 停止某个软件定时器 */
void bsp_StopTimer(uint8_t _id)
{
	if(_id > TMR_COUNT)
	{
		printf("Timer ID Error!\n");
		return ;
	}

	DISABLE_INT();

	s_tTmr[_id].Count = 0;						// 计数值
	s_tTmr[_id].Flag = 0;							// 复位定时时间到标志
	s_tTmr[_id].Mode = TMR_ONCE_MODE;	// 单次模式

	ENABLE_INT();	
}

/**
 * @brief		检查某个软件定时器是否超时
 * @param		_id: 定时器ID号
 * @retval	0: 未超时  1: 超时
 * @note
 */
uint8_t bsp_CheckTimer(uint8_t _id)
{
	if(_id > TMR_COUNT)
	{
		printf("Timer ID Error!\n");
		return 0;
	}	

	if(s_tTmr[_id].Flag == 1)
	{
		s_tTmr[_id].Flag = 0;
		return 1;
	}
	else
	{
		return 0;
	}
}

/* 获取系统运行时间 */
int32_t bsp_GetRunTime(void)
{
	int32_t runTime;

	DISABLE_INT();

	runTime = g_iRunTime;

	ENABLE_INT();

	return runTime;
}

/**
 * @brief		计算当前时间和上个时刻(自主标记)的时间差值 
 * @param		_LastTime: 上个时刻的系统时间
 * @retval	二者之间的时间差值,单位1ms
 * @note		注意变量溢出时的计算格式
 */
int32_t bsp_CheckRunTime(int32_t _LastTime)
{
	int32_t nowTime;
	int32_t timeDiff;

	DISABLE_INT();

	nowTime = g_iRunTime;

	ENABLE_INT();

	if(nowTime >= _LastTime)
	{
		timeDiff = nowTime - _LastTime;
	}
	else
	{
		timeDiff = 0x7FFFFFFF - _LastTime  + nowTime;
	}
	
	return timeDiff;
}

/* 每1ms执行一次 */
void bsp_RunPer1ms(void)
{

}

/* 每10ms执行一次 */
void bsp_RunPer10ms(void)
{

}

/**
 * @brief		硬件定时器,定时时间到执行回调函数
 						定时精度正负10us （主要耗费在调用本函数的执行时间，函数内部进行了补偿减小误差）
 * @param		_CC: 捕获通道
 * @param		ucTimeOut: 超时时间 时基：1us
 * @param		_pCallBack: 回调函数
 * @retval	None
 * @note		使用是捕获比较中断
 */
void bsp_startHardTimer(uint8_t _CC, uint32_t ucTimeOut, void *_pCallBack)
{
    uint32_t cnt_now;
    uint32_t cnt_tar;

		if(ucTimeOut < 5)
		{
			;
		}
		else
		{
			ucTimeOut -= 5;		// 减小误差用
		}

		cnt_now = __HAL_TIM_GetCounter(&htim3);		// 读取当前计算值
		cnt_tar = cnt_now + ucTimeOut;						// 计算捕获计算值
		if(_CC == 1)
		{
			// 注册回调函数
			s_TIM_CallBack1 = (void (*)(void))_pCallBack;
			// 设置捕获值
			__HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_1, cnt_tar);
			__HAL_TIM_CLEAR_IT(&htim3, TIM_IT_CC1);
			__HAL_TIM_ENABLE_IT(&htim3, TIM_IT_CC1);		// 使能CC1中断
		}
		else if(_CC == 2)
		{
			
		}
		else if(_CC == 3)
		{
			
		}		
		else if(_CC == 4)
		{
			
		}		
		else
		{
			return ;
		}
}

